package org.nf.web.param;

import cn.hutool.core.util.ReflectUtil;
import org.nf.web.annotation.Model;
import org.nf.web.common.TypeConvertor;
import org.nf.web.servlet.MethodArgumentsResolver;
import org.nf.web.servlet.ServletApi;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Parameter;
import java.util.ServiceLoader;

/**
 * 对象参数解析器
 *
 * @author zhu
 * @date 2024-05-17
 */
public class ModelMethodArgumentResolver implements MethodArgumentsResolver {

    private final ServiceLoader<TypeConvertor> loader = ServiceLoader.load(TypeConvertor.class);
    @Override
    public Object resolve(Parameter parameter, ServletApi servletApi) {

        try {
            // 获取参数的Class类型
            Class<?> parameterType = parameter.getType();
            Object instance = ReflectUtil.newInstance(parameterType);
            BeanInfo beanInfo = Introspector.getBeanInfo(parameterType, Object.class);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                // 获取字段名称，这个名称需要和请求参数的name保持一致
                String name = property.getName();
                // 获取请求参数
                String value = servletApi.req().getParameter(name);
                // 获取字段的class类型
                Class<?> propertyType = property.getPropertyType();

                for (TypeConvertor typeConvertor : loader) {
                    if (typeConvertor.supports(propertyType)) {
                        if (value != null) {
                            Object obj = typeConvertor.convert(value);
                            ReflectUtil.invoke(instance, property.getWriteMethod(), obj);
                        }
                    }
                }
            }
            return instance;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean supports(Parameter parameter) {
        return parameter.isAnnotationPresent(Model.class);
    }
}
